import inspect
from functools import lru_cache
from functools import lru_cache
from typing import Annotated

import numpy as np
import pandas as pd
import scipy
from langchain_core.tools import tool
from langgraph.prebuilt import ToolNode
from openai import OpenAI

from app.agent.factors.factor_lib import factor_bond_trading_signals
from app.agent.state import QuantState
from app.agent.utils import load_bond_data, build_prompt, calculate_max_drawdown, load_fx_data, parse_factors, \
    load_metal_data, preprocess_metal_data
from app.agent.utils import parse_factors_response, handle_missing_data
from app.utils import monitor
from textblob import TextBlob


def read_json_template(file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        # 读取文件的全部内容并存储为字符串
        template = file.read()
        return template


@tool
def ds_search(query: Annotated[str, "查询内容"]) -> str:
    """搜索deepseek"""
    client = OpenAI(api_key="sk-70a80512c5ab417481f2616c45eea492", base_url="https://api.deepseek.com")
    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=[
            {"role": "system", "content": "You are a helpful assistant"},
            {"role": "user", "content": '"' + query + '"'},
        ],
        stream=False
    )
    return response.choices[0].message.content


@tool
def kimi_search(query: Annotated[str, "查询内容"]) -> str:
    """搜索kimi"""
    client = OpenAI(
        api_key="sk-AwewtmuthfE9ta8XzDe2duihkC57e4duvcGLrbCfExJqAwWo",
        base_url="https://api.moonshot.cn/v1",
    )
    completion = client.chat.completions.create(
        model="moonshot-v1-8k",
        messages=[
            {"role": "system",
             "content": "你是 Kimi，由 Moonshot AI 提供的人工智能助手，你更擅长中文和英文的对话。你会为用户提供安全，有帮助，准确的回答。同时，你会拒绝一切涉及恐怖主义，种族歧视，黄色暴力等问题的回答。Moonshot AI 为专有名词，不可翻译成其他语言。"},
            {"role": "user", "content": '"' + query + '"'}
        ],
        temperature=0.3,
    )

    return completion.choices[0].message.content


@lru_cache(maxsize=4)
def _get_model():
    search_tools = [ds_search]
    ToolNode(search_tools)
    return ds_search


def load_data(state: QuantState) -> QuantState:
    df = None
    if state["params"]["asset_class"] == "外汇":
        df = load_fx_data(
            pair=state["params"]["currency_pair"],
            timeframe=state["params"]["time_frame"]
        )
    elif state["params"]["asset_class"] == "债券":
        df = load_bond_data(
            duration=state["params"]["bond_duration"],
            rating=state["params"]["credit_rating"]
        )
    elif state["params"]["asset_class"] == "贵金属":
        state["raw_data"] = load_metal_data(state["params"])
    state["raw_data"] = df.to_dict("records")
    return state


def preprocess_data(state: QuantState) -> QuantState:
    raw_data = state["raw_data"]
    ac = state["params"]["asset_class"]
    if ac == "外汇" or ac == "债券":
        processed_data = handle_missing_data(pd.DataFrame(raw_data))
    elif ac == "贵金属":
        processed_data = preprocess_metal_data(raw_data)
    state["processed_data"] = processed_data.to_dict("records")
    return state


# ========== 外汇专用节点 ==========

def fx_feature_engineering(state: QuantState):
    """外汇特征工程"""
    data = state["raw_data"]
    df = pd.DataFrame(data)
    # 订单簿不平衡度
    df["order_imbalance"] = (df["bid_qty"] - df["ask_qty"]) / (df["bid_qty"] + df["ask_qty"])

    # 隔夜利息差=基础货币汇率-报价货币汇率
    # df["swap_rate"] = df["base_currency_rate"] - df["quote_currency_rate"]

    state["features"] = df.to_dict("records")
    return state


# ========== 债券专用节点 ==========

def bond_feature_engineering(state: QuantState):
    """债券特征工程"""
    data = state["raw_data"]
    df = pd.DataFrame(data)

    # 久期调整收益率
    df["duration_adj"] = df["yield"] * df["modified_duration"]

    # 信用利差变化率
    df["credit_spread_chg"] = df["corporate_spread"].pct_change()

    state["features"] = df.to_dict("records")

    return state


def metal_feature_engineering(state: QuantState):
    pd_data = state["processed_data"]
    df = pd.DataFrame(pd_data)
    state["features"] = technical_features(macro_features(df))
    return state


# from talib import abstract


def technical_features(df: pd.DataFrame) -> pd.DataFrame:
    """贵金属技术指标特征"""
    # 动量指标
    # df['RSI'] = abstract.RSI(df, timeperiod=14)
    # df['MACD'], _, _ = abstract.MACD(df)

    # 波动率特征
    df['HV20'] = df['close'].pct_change().rolling(20).std() * np.sqrt(252)

    return df


def macro_features(df: pd.DataFrame) -> pd.DataFrame:
    """宏观特征处理"""
    # 实际利率与价格关系
    df['price_real_rate'] = df['close'] * (1 + df['real_rate'])

    # 美元指数滞后效应
    df['dxy_impact'] = df['dxy'].shift(3) - df['dxy'].shift(10)

    return df


def metal_momentum_factor(data: pd.DataFrame) -> pd.Series:
    """贵金属动量趋势因子"""
    # 双均线系统
    fast_ma = data['close'].rolling(5).mean()
    slow_ma = data['close'].rolling(20).mean()
    signal = np.where(fast_ma > slow_ma, 1, -1)

    # 波动率调整
    signal = signal * (1 / data['HV20'].clip(lower=0.1))

    return pd.Series(signal, index=data.index)


def carry_cost_arb_factor(data: pd.DataFrame) -> pd.Series:
    """展期套利因子"""
    # 期货溢价计算
    futures_premium = data['close_futures'] / data['close_spot'] - 1

    # 持仓成本调整
    carry_signal = np.where(
        futures_premium > data['carry_cost'],
        1,  # 正向套利信号
        -1  # 反向套利信号
    )

    return pd.Series(carry_signal, index=data.index)


def etf_flow_factor(data: pd.DataFrame) -> pd.Series:
    """ETF资金流因子"""
    flow = data['etf_holdings'].diff(3)
    return (flow - flow.rolling(20).mean()) / flow.rolling(20).std()


def generate_factors(state: QuantState) -> QuantState:
    """调用大模型生成因子"""
    prompt = build_prompt(state["params"], pd.DataFrame(state["features"]).columns.tolist())
    llm_response = _get_model().invoke(prompt)
    valid_factors, factors_names = parse_factors(llm_response)
    state["candidate_factors"] = valid_factors
    state["factors_names"] = factors_names
    # print(valid_factors, factors_names)
    return state




def backtest_factor(state: QuantState) -> QuantState:
    """因子回测验证"""
    reports = {}
    for factor_code in state["candidate_factors"]:
        # 执行回测（示例简化逻辑）
        exec(factor_code)
        factor_name = state["factors_names"][0]
        fnc = locals()[factor_name]
        # Prepare arguments dynamically
        df = pd.DataFrame(state["features"])
        args = []
        params = df.columns
        for param in params:
            if param in df.columns:
                args.append(df[param])
            else:
                # Provide default value if column missing
                if params[param].default is inspect.Parameter.empty:
                    raise ValueError(f"Required column '{param}' not found in DataFrame")
                args.append(params[param].default)
        returns = fnc(*args)
        print(returns)
        # returns = exec(factor, state["features"])
        sharpe = returns.mean() / returns.std() * np.sqrt(252)
        reports[factor_name] = {
            "sharpe": sharpe,
            "max_dd": calculate_max_drawdown(returns)
        }
    state["backtest_results"] = reports
    return state


def evaluate_factors(state: QuantState) -> QuantState:
    # 筛选标准：夏普>1，回撤<20%
    selected = [
        factor for factor, metrics in state["backtest_results"].items()
        if metrics["sharpe"] > 0.5 and metrics["max_dd"] < 0
    ]
    state["selected_factors"] = selected
    # 产生假因子，后续需要修改
    return state


def code_executor(code_str, function_name, *args, **kwargs):
    # 创建一个空的命名空间
    namespace = {}
    try:
        # 执行代码字符串，将函数加载到命名空间中
        exec(code_str, namespace)
        # 检查函数是否存在于命名空间中
        if function_name in namespace:
            # 获取函数对象
            func = namespace[function_name]
            # 调用函数并传入参数
            result = func(*args, **kwargs)
            return result
        else:
            return f"函数 {function_name} 未在代码中定义。"
    except Exception as e:
        return f"执行代码时出现错误: {str(e)}"
